/*
 *
 *    Copyright (c) 2022 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

// THIS FILE IS GENERATED BY ZAP

#pragma once

#include "TestCommand.h"

class Test_TC_DM_1_3_SimulatedSuite : public TestCommand
{
public:
    Test_TC_DM_1_3_SimulatedSuite() : TestCommand("Test_TC_DM_1_3_Simulated"), mTestIndex(0)
    {
        AddArgument("nodeId", 0, UINT64_MAX, &mNodeId);
        AddArgument("cluster", &mCluster);
        AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint);
        AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
    }

    ~Test_TC_DM_1_3_SimulatedSuite() {}

    /////////// TestCommand Interface /////////
    void NextTest() override
    {
        CHIP_ERROR err = CHIP_NO_ERROR;

        if (0 == mTestIndex)
        {
            ChipLogProgress(chipTool, " **** Test Start: Test_TC_DM_1_3_Simulated\n");
        }

        if (mTestCount == mTestIndex)
        {
            ChipLogProgress(chipTool, " **** Test Complete: Test_TC_DM_1_3_Simulated\n");
            SetCommandExitStatus(CHIP_NO_ERROR);
            return;
        }

        Wait();

        // Ensure we increment mTestIndex before we start running the relevant
        // command.  That way if we lose the timeslice after we send the message
        // but before our function call returns, we won't end up with an
        // incorrect mTestIndex value observed when we get the response.
        switch (mTestIndex++)
        {
        case 0:
            ChipLogProgress(chipTool, " ***** Test Step 0 : Wait for the device to be commissioned\n");
            err = TestWaitForTheDeviceToBeCommissioned_0();
            break;
        case 1:
            ChipLogProgress(chipTool, " ***** Test Step 1 : Log OnOff Test Startup\n");
            err = TestLogOnOffTestStartup_1();
            break;
        case 2:
            ChipLogProgress(chipTool, " ***** Test Step 2 : Query Data Model Revision\n");
            err = TestQueryDataModelRevision_2();
            break;
        case 3:
            ChipLogProgress(chipTool, " ***** Test Step 3 : Query Vendor Name\n");
            err = TestQueryVendorName_3();
            break;
        case 4:
            ChipLogProgress(chipTool, " ***** Test Step 4 : Query VendorID\n");
            err = TestQueryVendorID_4();
            break;
        case 5:
            ChipLogProgress(chipTool, " ***** Test Step 5 : Query Product Name\n");
            err = TestQueryProductName_5();
            break;
        case 6:
            ChipLogProgress(chipTool, " ***** Test Step 6 : Query ProductID\n");
            err = TestQueryProductID_6();
            break;
        case 7:
            ChipLogProgress(chipTool, " ***** Test Step 7 : Query Node Label\n");
            err = TestQueryNodeLabel_7();
            break;
        case 8:
            ChipLogProgress(chipTool, " ***** Test Step 8 : Query User Location\n");
            err = TestQueryUserLocation_8();
            break;
        case 9:
            ChipLogProgress(chipTool, " ***** Test Step 9 : Query HardwareVersion\n");
            err = TestQueryHardwareVersion_9();
            break;
        case 10:
            ChipLogProgress(chipTool, " ***** Test Step 10 : Query HardwareVersionString\n");
            err = TestQueryHardwareVersionString_10();
            break;
        case 11:
            ChipLogProgress(chipTool, " ***** Test Step 11 : Query SoftwareVersion\n");
            err = TestQuerySoftwareVersion_11();
            break;
        case 12:
            ChipLogProgress(chipTool, " ***** Test Step 12 : Query SoftwareVersionString\n");
            err = TestQuerySoftwareVersionString_12();
            break;
        case 13:
            ChipLogProgress(chipTool, " ***** Test Step 13 : Query ManufacturingDate\n");
            err = TestQueryManufacturingDate_13();
            break;
        case 14:
            ChipLogProgress(chipTool, " ***** Test Step 14 : Query PartNumber\n");
            err = TestQueryPartNumber_14();
            break;
        case 15:
            ChipLogProgress(chipTool, " ***** Test Step 15 : Query ProductURL\n");
            err = TestQueryProductURL_15();
            break;
        case 16:
            ChipLogProgress(chipTool, " ***** Test Step 16 : Query ProductLabel\n");
            err = TestQueryProductLabel_16();
            break;
        case 17:
            ChipLogProgress(chipTool, " ***** Test Step 17 : Query SerialNumber\n");
            err = TestQuerySerialNumber_17();
            break;
        case 18:
            ChipLogProgress(chipTool, " ***** Test Step 18 : Query LocalConfigDisabled\n");
            err = TestQueryLocalConfigDisabled_18();
            break;
        case 19:
            ChipLogProgress(chipTool, " ***** Test Step 19 : Query Reachable\n");
            err = TestQueryReachable_19();
            break;
        case 20:
            ChipLogProgress(chipTool, " ***** Test Step 20 : Query UniqueID\n");
            err = TestQueryUniqueID_20();
            break;
        }

        if (CHIP_NO_ERROR != err)
        {
            ChipLogError(chipTool, " ***** Test Failure: %s\n", chip::ErrorStr(err));
            SetCommandExitStatus(err);
        }
    }

private:
    std::atomic_uint16_t mTestIndex;
    const uint16_t mTestCount = 21;

    chip::Optional<chip::NodeId> mNodeId;
    chip::Optional<chip::CharSpan> mCluster;
    chip::Optional<chip::EndpointId> mEndpoint;
    chip::Optional<uint16_t> mTimeout;

    void OnDiscoveryCommandsResults(const DiscoveryCommandResult & value) override
    {
        bool isExpectedDnssdResult = false;

        VerifyOrReturn(isExpectedDnssdResult, Exit("An unexpected dnssd result has been received"));
        NextTest();
    }

    //
    // Tests methods
    //

    CHIP_ERROR TestWaitForTheDeviceToBeCommissioned_0()
    {
        SetIdentity(kIdentityAlpha);
        return WaitForCommissioning();
    }

    CHIP_ERROR TestLogOnOffTestStartup_1()
    {
        SetIdentity(kIdentityAlpha);
        return Log("*** Basic Cluster Tests Ready");
    }

    CHIP_ERROR TestQueryDataModelRevision_2()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: DataModelRevision] Query Data Model Revision",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::DataModelRevision::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryVendorName_3()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: VendorName] Query Vendor Name", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::VendorName::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryVendorID_4()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: VendorID] Query VendorID", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::VendorID::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryProductName_5()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: ProductName] Query Product Name", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::ProductName::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryProductID_6()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: ProductID] Query ProductID", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::ProductID::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryNodeLabel_7()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: NodeLabel] Query Node Label", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::NodeLabel::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryUserLocation_8()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: Location] Query User Location", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::Location::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryHardwareVersion_9()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: HardwareVersion] Query HardwareVersion", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::HardwareVersion::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryHardwareVersionString_10()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: HardwareVersionString] Query HardwareVersionString",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::HardwareVersionString::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQuerySoftwareVersion_11()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: SoftwareVersion] Query SoftwareVersion", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::SoftwareVersion::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQuerySoftwareVersionString_12()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: SoftwareVersionString] Query SoftwareVersionString",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::SoftwareVersionString::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryManufacturingDate_13()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: ManufacturingDate] Query ManufacturingDate", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::ManufacturingDate::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryPartNumber_14()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: PartNumber] Query PartNumber", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::PartNumber::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryProductURL_15()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: ProductURL] Query ProductURL", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::ProductURL::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryProductLabel_16()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: ProductLabel] Query ProductLabel", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::ProductLabel::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQuerySerialNumber_17()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: SerialNumber] Query SerialNumber", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::SerialNumber::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryLocalConfigDisabled_18()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: LocalConfigDisabled] Query LocalConfigDisabled",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::LocalConfigDisabled::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryReachable_19()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: Reachable] Query Reachable", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::Reachable::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestQueryUniqueID_20()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Basic Attribute: UniqueID] Query UniqueID", endpoint);

        ClearAttributeAndCommandPaths();
        mAttributePath = chip::app::ConcreteAttributePath(endpoint, chip::app::Clusters::Basic::Id,
                                                          chip::app::Clusters::Basic::Attributes::UniqueID::Id);
        return CHIP_NO_ERROR;
    }
};

class Test_TC_DM_3_3_SimulatedSuite : public TestCommand
{
public:
    Test_TC_DM_3_3_SimulatedSuite() : TestCommand("Test_TC_DM_3_3_Simulated"), mTestIndex(0)
    {
        AddArgument("nodeId", 0, UINT64_MAX, &mNodeId);
        AddArgument("cluster", &mCluster);
        AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint);
        AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
    }

    ~Test_TC_DM_3_3_SimulatedSuite() {}

    /////////// TestCommand Interface /////////
    void NextTest() override
    {
        CHIP_ERROR err = CHIP_NO_ERROR;

        if (0 == mTestIndex)
        {
            ChipLogProgress(chipTool, " **** Test Start: Test_TC_DM_3_3_Simulated\n");
        }

        if (mTestCount == mTestIndex)
        {
            ChipLogProgress(chipTool, " **** Test Complete: Test_TC_DM_3_3_Simulated\n");
            SetCommandExitStatus(CHIP_NO_ERROR);
            return;
        }

        Wait();

        // Ensure we increment mTestIndex before we start running the relevant
        // command.  That way if we lose the timeslice after we send the message
        // but before our function call returns, we won't end up with an
        // incorrect mTestIndex value observed when we get the response.
        switch (mTestIndex++)
        {
        case 0:
            ChipLogProgress(chipTool, " ***** Test Step 0 : Wait for the device to be commissioned\n");
            err = TestWaitForTheDeviceToBeCommissioned_0();
            break;
        case 1:
            ChipLogProgress(chipTool, " ***** Test Step 1 : Wait for Scan Network Command\n");
            err = TestWaitForScanNetworkCommand_1();
            break;
        case 2:
            ChipLogProgress(chipTool, " ***** Test Step 2 : Wait for Add Wifi Network Command\n");
            if (ShouldSkip("WIFI"))
            {
                NextTest();
                return;
            }
            err = TestWaitForAddWifiNetworkCommand_2();
            break;
        case 3:
            ChipLogProgress(chipTool, " ***** Test Step 3 : Wait for Update Thread Network Command\n");
            if (ShouldSkip("THREAD"))
            {
                NextTest();
                return;
            }
            err = TestWaitForUpdateThreadNetworkCommand_3();
            break;
        case 4:
            ChipLogProgress(chipTool, " ***** Test Step 4 : Wait for Enable Network Command\n");
            err = TestWaitForEnableNetworkCommand_4();
            break;
        case 5:
            ChipLogProgress(chipTool, " ***** Test Step 5 : Wait for Remove Network Command\n");
            if (ShouldSkip("WIFI | THREAD"))
            {
                NextTest();
                return;
            }
            err = TestWaitForRemoveNetworkCommand_5();
            break;
        }

        if (CHIP_NO_ERROR != err)
        {
            ChipLogError(chipTool, " ***** Test Failure: %s\n", chip::ErrorStr(err));
            SetCommandExitStatus(err);
        }
    }

private:
    std::atomic_uint16_t mTestIndex;
    const uint16_t mTestCount = 6;

    chip::Optional<chip::NodeId> mNodeId;
    chip::Optional<chip::CharSpan> mCluster;
    chip::Optional<chip::EndpointId> mEndpoint;
    chip::Optional<uint16_t> mTimeout;

    void OnDiscoveryCommandsResults(const DiscoveryCommandResult & value) override
    {
        bool isExpectedDnssdResult = false;

        VerifyOrReturn(isExpectedDnssdResult, Exit("An unexpected dnssd result has been received"));
        NextTest();
    }

    //
    // Tests methods
    //

    CHIP_ERROR TestWaitForTheDeviceToBeCommissioned_0()
    {
        SetIdentity(kIdentityAlpha);
        return WaitForCommissioning();
    }

    CHIP_ERROR TestWaitForScanNetworkCommand_1()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool,
                     "[Endpoint: 0x%08x Cluster: Network Commissioning Command: ScanNetworks] Wait for Scan Network Command",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath = chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::NetworkCommissioning::Id,
                                                      chip::app::Clusters::NetworkCommissioning::Commands::ScanNetworks::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForAddWifiNetworkCommand_2()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(
            chipTool,
            "[Endpoint: 0x%08x Cluster: Network Commissioning Command: AddOrUpdateWiFiNetwork] Wait for Add Wifi Network Command",
            endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath =
            chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::NetworkCommissioning::Id,
                                           chip::app::Clusters::NetworkCommissioning::Commands::AddOrUpdateWiFiNetwork::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForUpdateThreadNetworkCommand_3()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool,
                     "[Endpoint: 0x%08x Cluster: Network Commissioning Command: AddOrUpdateThreadNetwork] Wait for Update Thread "
                     "Network Command",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath =
            chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::NetworkCommissioning::Id,
                                           chip::app::Clusters::NetworkCommissioning::Commands::AddOrUpdateThreadNetwork::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForEnableNetworkCommand_4()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool,
                     "[Endpoint: 0x%08x Cluster: Network Commissioning Command: ConnectNetwork] Wait for Enable Network Command",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath = chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::NetworkCommissioning::Id,
                                                      chip::app::Clusters::NetworkCommissioning::Commands::ConnectNetwork::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForRemoveNetworkCommand_5()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool,
                     "[Endpoint: 0x%08x Cluster: Network Commissioning Command: RemoveNetwork] Wait for Remove Network Command",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath = chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::NetworkCommissioning::Id,
                                                      chip::app::Clusters::NetworkCommissioning::Commands::RemoveNetwork::Id);
        return CHIP_NO_ERROR;
    }
};

class Test_TC_DM_2_3_SimulatedSuite : public TestCommand
{
public:
    Test_TC_DM_2_3_SimulatedSuite() : TestCommand("Test_TC_DM_2_3_Simulated"), mTestIndex(0)
    {
        AddArgument("nodeId", 0, UINT64_MAX, &mNodeId);
        AddArgument("cluster", &mCluster);
        AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint);
        AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
    }

    ~Test_TC_DM_2_3_SimulatedSuite() {}

    /////////// TestCommand Interface /////////
    void NextTest() override
    {
        CHIP_ERROR err = CHIP_NO_ERROR;

        if (0 == mTestIndex)
        {
            ChipLogProgress(chipTool, " **** Test Start: Test_TC_DM_2_3_Simulated\n");
        }

        if (mTestCount == mTestIndex)
        {
            ChipLogProgress(chipTool, " **** Test Complete: Test_TC_DM_2_3_Simulated\n");
            SetCommandExitStatus(CHIP_NO_ERROR);
            return;
        }

        Wait();

        // Ensure we increment mTestIndex before we start running the relevant
        // command.  That way if we lose the timeslice after we send the message
        // but before our function call returns, we won't end up with an
        // incorrect mTestIndex value observed when we get the response.
        switch (mTestIndex++)
        {
        case 0:
            ChipLogProgress(chipTool, " ***** Test Step 0 : Wait for Arm Fail Safe\n");
            err = TestWaitForArmFailSafe_0();
            break;
        case 1:
            ChipLogProgress(chipTool, " ***** Test Step 1 : Wait for Set Regulatory Config\n");
            err = TestWaitForSetRegulatoryConfig_1();
            break;
        case 2:
            ChipLogProgress(chipTool, " ***** Test Step 2 : Wait for Attestation Certificate Chain Request\n");
            err = TestWaitForAttestationCertificateChainRequest_2();
            break;
        case 3:
            ChipLogProgress(chipTool, " ***** Test Step 3 : Wait for Attestation Certificate Chain Request\n");
            err = TestWaitForAttestationCertificateChainRequest_3();
            break;
        case 4:
            ChipLogProgress(chipTool, " ***** Test Step 4 : Wait for Attestation Request\n");
            err = TestWaitForAttestationRequest_4();
            break;
        case 5:
            ChipLogProgress(chipTool, " ***** Test Step 5 : Wait for CSR Request\n");
            err = TestWaitForCsrRequest_5();
            break;
        case 6:
            ChipLogProgress(chipTool, " ***** Test Step 6 : Wait for Add Trusted Root Certificate Request\n");
            err = TestWaitForAddTrustedRootCertificateRequest_6();
            break;
        case 7:
            ChipLogProgress(chipTool, " ***** Test Step 7 : Wait for Add Op NOC\n");
            err = TestWaitForAddOpNoc_7();
            break;
        case 8:
            ChipLogProgress(chipTool, " ***** Test Step 8 : Wait for Commissioning Complete\n");
            err = TestWaitForCommissioningComplete_8();
            break;
        case 9:
            ChipLogProgress(chipTool, " ***** Test Step 9 : Wait 3000ms\n");
            err = TestWait3000ms_9();
            break;
        }

        if (CHIP_NO_ERROR != err)
        {
            ChipLogError(chipTool, " ***** Test Failure: %s\n", chip::ErrorStr(err));
            SetCommandExitStatus(err);
        }
    }

private:
    std::atomic_uint16_t mTestIndex;
    const uint16_t mTestCount = 10;

    chip::Optional<chip::NodeId> mNodeId;
    chip::Optional<chip::CharSpan> mCluster;
    chip::Optional<chip::EndpointId> mEndpoint;
    chip::Optional<uint16_t> mTimeout;

    void OnDiscoveryCommandsResults(const DiscoveryCommandResult & value) override
    {
        bool isExpectedDnssdResult = false;

        VerifyOrReturn(isExpectedDnssdResult, Exit("An unexpected dnssd result has been received"));
        NextTest();
    }

    //
    // Tests methods
    //

    CHIP_ERROR TestWaitForArmFailSafe_0()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: General Commissioning Command: ArmFailSafe] Wait for Arm Fail Safe",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath = chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::GeneralCommissioning::Id,
                                                      chip::app::Clusters::GeneralCommissioning::Commands::ArmFailSafe::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForSetRegulatoryConfig_1()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(
            chipTool,
            "[Endpoint: 0x%08x Cluster: General Commissioning Command: SetRegulatoryConfig] Wait for Set Regulatory Config",
            endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath = chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::GeneralCommissioning::Id,
                                                      chip::app::Clusters::GeneralCommissioning::Commands::SetRegulatoryConfig::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForAttestationCertificateChainRequest_2()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool,
                     "[Endpoint: 0x%08x Cluster: Operational Credentials Command: CertificateChainRequest] Wait for Attestation "
                     "Certificate Chain Request",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath =
            chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::OperationalCredentials::Id,
                                           chip::app::Clusters::OperationalCredentials::Commands::CertificateChainRequest::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForAttestationCertificateChainRequest_3()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool,
                     "[Endpoint: 0x%08x Cluster: Operational Credentials Command: CertificateChainRequest] Wait for Attestation "
                     "Certificate Chain Request",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath =
            chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::OperationalCredentials::Id,
                                           chip::app::Clusters::OperationalCredentials::Commands::CertificateChainRequest::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForAttestationRequest_4()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool,
                     "[Endpoint: 0x%08x Cluster: Operational Credentials Command: AttestationRequest] Wait for Attestation Request",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath =
            chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::OperationalCredentials::Id,
                                           chip::app::Clusters::OperationalCredentials::Commands::AttestationRequest::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForCsrRequest_5()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Operational Credentials Command: CSRRequest] Wait for CSR Request",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath = chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::OperationalCredentials::Id,
                                                      chip::app::Clusters::OperationalCredentials::Commands::CSRRequest::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForAddTrustedRootCertificateRequest_6()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool,
                     "[Endpoint: 0x%08x Cluster: Operational Credentials Command: AddTrustedRootCertificate] Wait for Add Trusted "
                     "Root Certificate Request",
                     endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath =
            chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::OperationalCredentials::Id,
                                           chip::app::Clusters::OperationalCredentials::Commands::AddTrustedRootCertificate::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForAddOpNoc_7()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(chipTool, "[Endpoint: 0x%08x Cluster: Operational Credentials Command: AddNOC] Wait for Add Op NOC", endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath = chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::OperationalCredentials::Id,
                                                      chip::app::Clusters::OperationalCredentials::Commands::AddNOC::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWaitForCommissioningComplete_8()
    {
        const chip::EndpointId endpoint = mEndpoint.HasValue() ? mEndpoint.Value() : 0;
        ChipLogError(
            chipTool,
            "[Endpoint: 0x%08x Cluster: General Commissioning Command: CommissioningComplete] Wait for Commissioning Complete",
            endpoint);

        ClearAttributeAndCommandPaths();
        mCommandPath =
            chip::app::ConcreteCommandPath(endpoint, chip::app::Clusters::GeneralCommissioning::Id,
                                           chip::app::Clusters::GeneralCommissioning::Commands::CommissioningComplete::Id);
        return CHIP_NO_ERROR;
    }

    CHIP_ERROR TestWait3000ms_9()
    {
        SetIdentity(kIdentityAlpha);
        return WaitForMs(3000);
    }
};

std::unique_ptr<TestCommand> GetTestCommand(std::string testName)
{
    if (testName == "Test_TC_DM_1_3_Simulated")
    {
        return std::unique_ptr<Test_TC_DM_1_3_SimulatedSuite>(new Test_TC_DM_1_3_SimulatedSuite());
    }
    if (testName == "Test_TC_DM_3_3_Simulated")
    {
        return std::unique_ptr<Test_TC_DM_3_3_SimulatedSuite>(new Test_TC_DM_3_3_SimulatedSuite());
    }
    if (testName == "Test_TC_DM_2_3_Simulated")
    {
        return std::unique_ptr<Test_TC_DM_2_3_SimulatedSuite>(new Test_TC_DM_2_3_SimulatedSuite());
    }

    return nullptr;
}

void PrintTestCommands()
{
    ChipLogError(chipTool, "Supported commands:");
    ChipLogError(chipTool, "\t* Test_TC_DM_1_3_Simulated");
    ChipLogError(chipTool, "\t* Test_TC_DM_3_3_Simulated");
    ChipLogError(chipTool, "\t* Test_TC_DM_2_3_Simulated");
}
